# Licensed under the GNU Lesser General Public License, version 2.1 (LGPL-2.1)
# Full text is available at:
#
#    http://www.gnu.org/licenses/lgpl-2.1.txt
#
# This file is part of cyg-get.
#
#    cyg-get is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Lesser General Public License as
#    published by the Free Software Foundation, either version 2.1 of
#    the License, or (at your option) any later version.
#
#    cyg-get is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU Lesser General Public
#    License along with cyg-get.
#
#    If not, see <http://www.gnu.org/licenses/>.

package Cygwin::Db;

use strict;

use Cygwin::Package;
use Cygwin::Source;

use Data::Dumper::Simple;

sub new {
    my $class = shift;
    my $this = bless {}, $class;
    
    $this->{path} = shift;
    $this->{db} = {};
    load($this);
    
    return $this;
}

sub load {
    my $this = shift;
    my $path = shift;
    
    if( defined($path) ) {
        $this->{path} = $path;
    }
    
    if( !defined($this->{path}) ) {
        $this->{path} = "/etc/setup/installed.db";
    }
    
    my $db = $this->{db};
    
    open( FH, "<", $this->{path} );
    <FH>;
    foreach my $line (<FH>) {
        my $pkg = Cygwin::Package->new();
        $pkg->dbLine($line);
        $db->{$pkg->{name}} = $pkg;
    }
    close(FH);
}

sub find {
    my $this = shift;
    my @results = ();
    
    foreach (@_) {
        foreach my $key (keys %{$this->{db}}) {
            if( $key =~ m{$_} ) {
                push @results, $key;
            }
        }
    }
    
    return @results;
}
    
sub recadd {
    my $avail = shift;
    my $plist = shift;
    my $pkgs = shift;
    
    my @new = ();
    
    foreach my $p (@{$pkgs}) {
        if( !defined($plist->{$p}) ) {
            $plist->{$p} = 1;
            push @new, @{$avail->{$p}->{requires}};
        }
    }
    
    return if( 0 == scalar(@new) );
    
    @_ = ( $avail, $plist, \@new );
    goto &recadd;
}

sub addPackages {
    my $db = shift;
    my $pkgs = shift;
    
    my $oldfh;
    
    open( FH, ">>", $db );
    $oldfh = select FH;
    $|++;
    
    foreach my $p (keys %{$pkgs}) {
        print FH "$p " . $pkgs->{$p} . " 0\n";
    }
    
    select $oldfh;
    close(FH);
    
    system( "cp", $db, $db . ".bak");
    exec( "sort $db.bak > $db" );
}

sub postInstall {
    foreach my $p (@_) {
        if( -x "/etc/postinstall/$p" ) {
            print "/etc/postinstall/$p";
        }
    }
}

sub doInstall {
    my $this = shift;
    my $srcs = shift;
    my $pkgs = shift;
    
    my $var = "/var/lib/cyg-get/";
    #my $lists = $var . "lists";
    my $cache = $var . "cache";
    my %files = ();
    my ($url, $file);
    
PKG:foreach my $pkg (keys %{$pkgs}) {
LOC:    foreach my $loc (@{$srcs->{packages}->{$pkg}->{install}}) {
SRC:        foreach my $src (@{$srcs->{sources}}) {
                $url = $src . $loc;
                $url =~ m{.*/([^/\?]+)};
                $file = $1;
                if( !(-r "$cache/$file") ) {
                    system("lwp-download",
                           $src . $loc,
                           "$cache/");
                    unless( $? ) {
                        $files{$pkg} = $file;
                        last LOC;
                    }
                } else {
                    $files{$pkg} = $file;
                    last LOC;
                }
            }
            last LOC;  # only install the newest one
            # this needs to be much more intelligent
        }
    }
    
    foreach my $p (keys %files) {
        $file = "$cache/" . $files{$p};
        if( -r $file ) {
            print "Listing $p...";
            system( "tar tjf '$file' > '/etc/setup/$p.lst.gz'" );
            print " Done\n";
            
            print "Installing $p...";
            system( "tar xpPjf '$file' -C /" );
            
            if( $? ) {
                # Freak out?
                print " Failed\n";
            } else {
                print " Done\n";
                unlink $file;
            }
        }
    }
    
    postInstall( keys %files );
    addPackages( $this->{path}, \%files );
}

sub install {
    my $this = shift;
    my $src = shift;
    my $pkgs = shift;
    
    my %pkg_list = ();
    my $pkg;
    
    recadd( \%{$src->{packages}}, \%pkg_list, $pkgs );
    
    my @keys = keys %pkg_list;
    
    foreach my $key (@keys) {
        if( defined($this->{db}->{$key}) ) {
            delete $pkg_list{$key};
        }
    }
    
    doInstall( $this, $src, \%pkg_list );
}

1;